package com.wmapp.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.dom.DOMElement;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.wmapp.DomainConvertException;
import com.wmapp.connect.Request;
import com.wmapp.connect.SocketSupport;
import com.wmapp.domain.Administrator;
import com.wmapp.domain.SipAccount;
import com.wmapp.domain.BroadcastClient;
import com.wmapp.domain.CallDetail;
import com.wmapp.domain.ConfLayout;
import com.wmapp.domain.ConfMessage;
import com.wmapp.domain.ConfParticipant;
import com.wmapp.domain.ConfProfile;
import com.wmapp.domain.ConfReservation;
import com.wmapp.domain.Conference;
import com.wmapp.domain.ConferenceStatus;
import com.wmapp.domain.Email;
import com.wmapp.domain.MCU;
import com.wmapp.domain.Pane;
import com.wmapp.domain.Participant;
import com.wmapp.domain.ParticipantGroup;
import com.wmapp.domain.SMTP;
import com.wmapp.language.Lang;
import com.wmapp.sender.EmailSender;
import com.wmapp.service.ManagerService;
import com.wmapp.service.SetupService;
import com.wmapp.utils.DomainUtils;
import com.wmapp.utils.Pserver;
/**
 * This service is session scope.
 * @author dengl
 *
 */
public class ManagerServiceImpl extends SocketSupport implements ManagerService {
	private static Log log = LogFactory.getLog(ManagerServiceImpl.class);
	
	private SetupService setupService;
	
	private Lang lang;

	public void setSetupService(SetupService setupService) {
		this.setupService = setupService;
	}

	public void setLang(Lang lang) {
		this.lang = lang;
	}

	@Override
	public List<MCU> queryMCUList() {
		List<MCU> ret = new ArrayList<MCU>();
		Document doc=Pserver.getInstance().file2Document(Pserver.MCU_CONTEXT_FILE_NAME);
		List list = doc.selectNodes("/mcus/mcu");
		
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			Element e = (Element) iterator.next();
			MCU mcu = (MCU) DomainUtils.element2Domain(e,MCU.class);
			ret.add(mcu);
		}
		
		return ret;
	}
	
	@Override
	public void addMCU(MCU mcu) {
		mcu.setId(UUID.randomUUID().toString());
		Document doc=Pserver.getInstance().file2Document(Pserver.MCU_CONTEXT_FILE_NAME);
		
		doc.getRootElement().add(DomainUtils.domain2Element("mcu", mcu, MCU.XML_FIELDS));
		
		Pserver.getInstance().document2File(doc, Pserver.MCU_CONTEXT_FILE_NAME);
	}
	
	@Override
	public MCU getMCUByName(String name) {
		MCU mcu=null;
		Document doc=Pserver.getInstance().file2Document(Pserver.MCU_CONTEXT_FILE_NAME);
		List nodes=doc.selectNodes("/mcus/mcu/name");
		
		Node node=Pserver.getNodeByText(nodes, name);
		
		if(node!=null){
			mcu=(MCU)DomainUtils.element2Domain(node.getParent(), MCU.class);
		}
		
		return mcu;
	}
	
	@Override
	public boolean isNameExist(String name) {
		return getMCUByName(name)!=null;
	}
	
	@Override
	public void removeMCU(String id) {
		Document doc=Pserver.getInstance().file2Document(Pserver.MCU_CONTEXT_FILE_NAME);
		List nodes=doc.selectNodes("/mcus/mcu/id");
		
		Node node=Pserver.getNodeByText(nodes, id);
		
		if(node!=null){
			doc.getRootElement().remove(node.getParent());
		}
		
		Pserver.getInstance().document2File(doc, Pserver.MCU_CONTEXT_FILE_NAME);
	}
	
	@Override
	public MCU getMCUById(String id) {
		MCU mcu=null;
		Document doc=Pserver.getInstance().file2Document(Pserver.MCU_CONTEXT_FILE_NAME);
		List nodes=doc.selectNodes("/mcus/mcu/id");
		
		Node node=Pserver.getNodeByText(nodes, id);
		
		if(node!=null){
			mcu=(MCU)DomainUtils.element2Domain(node.getParent(), MCU.class);
		}
		return mcu;
	}
	
	@Override
	public void modifyMCU(MCU mcu) {
		if(mcu.getId()!=null){
			removeMCU(mcu.getId());
			addMCU(mcu);
		}
	}
	
	// -----------administrator------------
	@Override
	public void addAdmin(Administrator admin) {
		Map params=DomainUtils.domain2Map(admin, Administrator.ADD_PARAM_FIELDS);
		
		execute(Request.ADD_ADMIN_REQ,params,"administrator",true);
	}
	
	@Override
	public List<Administrator> queryAdminList() {
		List<Administrator> ret=null;
		
		String receive=execute(Request.GET_ADMIN_LIST_REQ);
		ret=DomainUtils.xml2List(receive,"/administrators/administrator",Administrator.class);
		return ret;
	}
	
	@Override
	public void removeAdmin(String names) {
		String[] nameArr=names.split(",");
		
		for (int i = 0; i < nameArr.length; i++) {
			Map map=new HashMap();
			map.put("name", nameArr[i]);
			execute(Request.DEL_ADMIN_REQ, map, "administrator",true);
		}
	}
	
	@Override
	public void modifyAdmin(Administrator admin) {
		Map param=DomainUtils.domain2Map(admin, Administrator.MODIFY_PARAM_FIELDS);
		
		execute(Request.PUT_ADMIN_REQ,param,"administrator",true);
	}
	
	@Override
	public Administrator getAdminByName(String name) {
		List<Administrator> list=queryAdminList();
		Administrator admin=null;
		
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			Administrator administrator = (Administrator) iterator.next();
			String tname=administrator.getName();
			
			if(tname!=null&&tname.equals(name)){
				admin=administrator;
				break;
			}
		}
		
		return admin;
	}
	
	@Override
	public boolean isAdminNameExist(String name) {
		return getAdminByName(name)!=null;
	}

    // -----------sip account------------
	@Override
	public void addSip(SipAccount sipAccount) {
		Map params=DomainUtils.domain2Map(sipAccount, SipAccount.ADD_PARAM_FIELDS);

		execute(Request.ADD_LINE_REQ,params,"line",true);
	}

	@Override
	public List<SipAccount> querySipList() {
		List<SipAccount> ret=null;

		String receive=execute(Request.GET_LINE_LIST_REQ);
		ret=DomainUtils.xml2List(receive,"/lines/line",SipAccount.class);
		return ret;
	}

	@Override
	public void removeSip(String names) {
		String[] nameArr=names.split(",");

		for (int i = 0; i < nameArr.length; i++) {
			Map map=new HashMap();
			map.put("line", nameArr[i]);
			execute(Request.DEL_LINE_REQ, map, "lines",true);
		}
	}

	@Override
	public void modifySip(SipAccount sipAccount) {
		Map param=DomainUtils.domain2Map(sipAccount, SipAccount.MODIFY_PARAM_FIELDS);

		execute(Request.PUT_LINE_REQ,param,"line",true);
	}

	@Override
	public SipAccount getSipByName(String name) {
		List<SipAccount> list=querySipList();
		SipAccount sip=null;

		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			SipAccount sipAccount = (SipAccount) iterator.next();
			String tname=sipAccount.getAccount();

			if(tname!=null&&tname.equals(name)){
				sip=sipAccount;
				break;
			}
		}

		return sip;
	}

	@Override
	public boolean isSipNameExist(String name) {
		return getSipByName(name)!=null;
	}
	
	//---------------ParticipantGroup------------------
	@Override
	public void addParticipantGroup(ParticipantGroup domain) {
		Map params=DomainUtils.domain2Map(domain, ParticipantGroup.ADD_PARAM_FIELDS);
		
		execute(Request.ADD_GROUP_REQ,params,"group",true);
	}
	
	@Override
	public List<ParticipantGroup> queryParticipantGroupList() {
		List<ParticipantGroup> ret=null;
		
		String receive=execute(Request.GET_GROUP_LIST_REQ);
		ret=DomainUtils.xml2List(receive,"/groups/group",ParticipantGroup.class);
		return ret;
	}
	
	@Override
	public void removeParticipantGroup(String names) {
		String[] nameArr=names.split(",");
		
		for (int i = 0; i < nameArr.length; i++) {
			Map map=new HashMap();
			map.put("name", nameArr[i]);
			execute(Request.DEL_GROUP_REQ, map, "group",true);
			//delete group members
			execute(Request.DEL_USER_GROUP_REQ, map, "group",true);
		}
	}
	
	@Override
	public void modifyParticipantGroup(ParticipantGroup domain) {
		Map param=DomainUtils.domain2Map(domain, ParticipantGroup.MODIFY_PARAM_FIELDS);
		
		execute(Request.PUT_GROUP_REQ,param,"group",true);
	}
	
	@Override
	public ParticipantGroup getParticipantGroupByName(String name) {
		List<ParticipantGroup> list=queryParticipantGroupList();
		ParticipantGroup ret=null;
		
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			ParticipantGroup domain = (ParticipantGroup) iterator.next();
			String tname=domain.getName();
			
			if(tname!=null&&tname.equals(name)){
				ret=domain;
				break;
			}
		}
		
		return ret;
	}
	
	@Override
	public boolean isParticipantGroupNameExist(String name) {
		return getParticipantGroupByName(name)!=null;
	}
	//---------------Participant------------------
	@Override
	public void addParticipant(Participant domain) {
		Map params=DomainUtils.domain2Map(domain, Participant.ADD_PARAM_FIELDS);
		
		execute(Request.ADD_USER_REQ,params,"user",true);
	}
	
	@Override
	public List<Participant> queryParticipantList() {
		List<Participant> ret=null;
		
		String receive=execute(Request.GET_USER_LIST_REQ);
		ret=DomainUtils.xml2List(receive,"/users/user",Participant.class);
		return ret;
	}
	
	@Override
	public void removeParticipant(String number) {
		String[] keyArray=number.split(",");
		
		for (int i = 0; i < keyArray.length; i++) {
			Map map=new HashMap();
			map.put("number", keyArray[i]);
			execute(Request.DEL_USER_REQ, map, "user",true);
		}
	}
	
	@Override
	public void modifyParticipant(Participant domain) {
		Map param=DomainUtils.domain2Map(domain, Participant.MODIFY_PARAM_FIELDS);
		
		execute(Request.PUT_USER_REQ,param,"user",true);
	}
	
	@Override
	public Participant getParticipantByKey(String key) {
		List<Participant> list=queryParticipantList();
		Participant ret=null;
		
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			Participant domain = (Participant) iterator.next();
			String _key=domain.getNumber();
			
			if(_key!=null&&_key.equals(key)){
				ret=domain;
				break;
			}
		}
		
		return ret;
	}
	
	@Override
	public boolean isParticipantExist(String key) {
		return getParticipantByKey(key)!=null;
	}
	
	//---------------ConfProfile------------------
	@Override
	public void addConfProfile(ConfProfile domain) {
		Map params=DomainUtils.domain2Map(domain, ConfProfile.ADD_PARAM_FIELDS);
		
		execute(Request.ADD_PROFILE_REQ,params,"profile",true);
	}
	
	@Override
	public List<ConfProfile> queryConfProfileList() {
		List<ConfProfile> ret=null;
		
		String receive=execute(Request.GET_PROFILE_LIST_REQ);
		ret=DomainUtils.xml2List(receive,"/profiles/profile",ConfProfile.class);
		return ret;
	}
	
	@Override
	public void removeConfProfile(String keys) {
		String[] keyArr=keys.split(",");
		
		for (int i = 0; i < keyArr.length; i++) {
			Map map=new HashMap();
			map.put("profileName", keyArr[i]);
			execute(Request.DEL_PROFILE_REQ, map, "profile",true);
		}
	}
	
	@Override
	public void modifyConfProfile(ConfProfile domain) {
		Map param=DomainUtils.domain2Map(domain, ConfProfile.MODIFY_PARAM_FIELDS);
		execute(Request.PUT_PROFILE_REQ,param,"profile",true);
	}
	
	@Override
	public ConfProfile getConfProfileByKey(String key) {
		List<ConfProfile> list=queryConfProfileList();
		ConfProfile ret=null;
		
		for (Iterator iterator = list.iterator(); iterator.hasNext();) {
			ConfProfile domain = (ConfProfile) iterator.next();
			String _key=domain.getProfileName();
			
			if(_key!=null&&_key.equals(key)){
				ret=domain;
				break;
			}
		}
		
		return ret;
	}
	
	@Override
	public boolean isConfProfileExist(String key) {
		return getConfProfileByKey(key)!=null;
	}
	
	//---------------Conference------------------
	@Override
	public void addConference(Conference domain) {
		Assert.notNull(domain);
		Document doc=DocumentHelper.createDocument();
		Element roomElement=DomainUtils.domain2Element("room", domain, Conference.ADD_PARAM_FIELDS);
		
		List<ConfParticipant> confParticipants=domain.getParticipants();
		Element participants=DocumentHelper.createElement("participants");
		for (Iterator iterator = confParticipants.iterator(); iterator
				.hasNext();) {
			ConfParticipant confParticipant = (ConfParticipant) iterator.next();
			participants.add(DomainUtils.domain2Element("participant", confParticipant, ConfParticipant.ADD_PARAM_FIELDS_FOR_INVITE));
		}
		
		if(participants.hasContent()){
			roomElement.add(participants);
		}
		
		doc.add(roomElement);
		execute(Request.ADD_ROOM_REQ,doc.asXML());
	}
	
	@Override
	public List<Conference> queryConferenceList() {
		List<Conference> ret=null;
		
		Map map = new HashMap<String,String>();
		map.put("started", "true");
		
		String receive=execute(Request.GET_ROOM_LIST_REQ,map);
		ret=DomainUtils.xml2List(receive,"/rooms/room",Conference.class);
		return ret;
	}
	
	@Override
	public void removeConference(String keys) {
		String[] keyArr=keys.split(",");
		
		for (int i = 0; i < keyArr.length; i++) {
			Map map=new HashMap();
			map.put("number", keyArr[i]);
			execute(Request.STOP_ROOM_REQ, map,"room");
		}
	}
        @Override
	public void pauseConference(String keys) {
		String[] keyArr=keys.split(",");

		for (int i = 0; i < keyArr.length; i++) {
			Map map=new HashMap();
			map.put("number", keyArr[i]);
			execute(Request.PAUSE_ROOM_REQ, map,"room");
		}
	}

         @Override
	public void restartConference(String keys) {
		String[] keyArr=keys.split(",");

		for (int i = 0; i < keyArr.length; i++) {
			Map map=new HashMap();
			map.put("number", keyArr[i]);
			execute(Request.RESTART_ROOM_REQ, map,"room");
		}
	}
	
	@Override
	public void modifyConference(Conference domain) {
		Assert.notNull(domain);
		Document doc=DocumentHelper.createDocument();
		Element roomElement=DomainUtils.domain2Element("room", domain, Conference.MODIFY_PARAM_FIELDS);
		
		List<ConfParticipant> confParticipants=domain.getParticipants();
		Element participants=DocumentHelper.createElement("participants");
		for (Iterator iterator = confParticipants.iterator(); iterator
				.hasNext();) {
			ConfParticipant confParticipant = (ConfParticipant) iterator.next();
			participants.add(DomainUtils.domain2Element("participant", confParticipant, ConfParticipant.MODIFY_PARAM_FIELDS_FOR_INVITE));
		}
		
		if(participants.hasContent()){
			roomElement.add(participants);
		}
		
		doc.add(roomElement);
		execute(Request.PUT_ROOM_REQ,doc.asXML());
	}
	
	@Override
	public Conference getConferenceByKey(String key) {
		Conference conf=null;
		
		Map param=new HashMap();
		param.put("number", key);
		String receiveXML=execute(Request.GET_ROOM_REQ, param);
		
		if(receiveXML!=null&&!receiveXML.equals("")){
			try {
				Document doc=DocumentHelper.parseText(receiveXML);
				Element root=doc.getRootElement();
				
				conf=(Conference)DomainUtils.element2Domain(root, Conference.class);
				List<ConfParticipant> list=new ArrayList<ConfParticipant>();
				List nodes=doc.selectNodes("/room//participants/participant");
				for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
					Element e = (Element) iterator.next();
					list.add((ConfParticipant)DomainUtils.element2Domain(e, ConfParticipant.class));
				}
				
				conf.setParticipants(list);
			} catch (DocumentException e) {
				throw new DomainConvertException(e.getMessage());
			}
		}
		
		
		return conf;
	}
	
	@Override
	public boolean isConferenceExist(String key) {
		return getConferenceByKey(key)!=null;
	}
	
	@Override
	public ConferenceStatus getConfStatus(String number) {
		ConferenceStatus ret=null;
		
		Map params=new HashMap<String, String>();
		params.put("number", number);
		String receiveXML=execute(Request.GET_ROOM_STATUS_REQ, params);
		
		try {
			Document doc=DocumentHelper.parseText(receiveXML);
			
			//retrieve base element value which has no sub elements from element to domain
			ret=(ConferenceStatus)DomainUtils.element2Domain(doc.getRootElement(), ConferenceStatus.class);
			List<Element> participants=doc.selectNodes("/room/participants/participant");
			List<Element> panes=doc.selectNodes("/room/panes/pane");
			
			//retrieve participants and panes element to relative list object
			List<Pane> paneList=ret.getPanes();
			List<ConfParticipant> participantList=ret.getParticipants();
			for (Iterator iterator = panes.iterator(); iterator.hasNext();) {
				Element element = (Element) iterator.next();
				paneList.add((Pane)DomainUtils.element2Domain(element,Pane.class));
			}
			for (Iterator iterator = participants.iterator(); iterator.hasNext();) {
				Element element = (Element) iterator.next();
				ConfParticipant confP=(ConfParticipant)DomainUtils.element2Domain(element, ConfParticipant.class);
				String callId=confP.getP_callId();
				//check the participant whether is lecture
				if(callId!=null&&ret.getLecture()!=null
						&&callId.equals(ret.getLecture())){
					confP.setLecture(true);
				}
				String h239Owner=ret.getH239TokenOwner();
				if(callId!=null&&h239Owner!=null
						&&callId.equals(h239Owner)){
					confP.setH239Owner(true);
					confP.setConfNumber(ret.getNumber());
				}
				if(callId!=null&&ret.getChairperson()!=null
						&&callId.equals(ret.getChairperson())){
					confP.setChairperson(true);
				}
				participantList.add(confP);
			}
		} catch (DocumentException e) { 
			log.error(e.getMessage());
			throw new DomainConvertException(e.getMessage());
		}
		
		return ret;
	}
	
	@Override
	public void saveCoustomLayout(ConfLayout confLayout) {
		Document doc=DocumentHelper.createDocument();
		
		Element root=DomainUtils.domain2Element("CTRL_ROOM_REQ", confLayout, ConfLayout.SAVE_PARAM_FIELDS);
		
		List<Pane> paneList=confLayout.getPanes();
		if(paneList!=null&&!paneList.isEmpty()){
			Element panes=root.addElement("panes");
			for (Iterator iterator = paneList.iterator(); iterator.hasNext();) {
				Pane pane = (Pane) iterator.next();
				panes.add(DomainUtils.domain2Element("pane", pane, Pane.SAVE_PARAM_FIELDS));
			}
		}
		
		doc.add(root);
		
		execute(Request.CTRL_ROOM_REQ,doc.asXML());
	}
	
	@Override
	public void autoLayout(String number) {
		Map param=new HashMap<String,String>();
		param.put("number", number);
		param.put("autoLayout", "true");
		
		execute(Request.CTRL_ROOM_REQ, param, "CTRL_ROOM_REQ");
	}
	
	@Override
	public void sendMessage(ConfMessage confMessage) {
		Map params=DomainUtils.domain2Map(confMessage, ConfMessage.SAVE_PARAM_FIELDS);
		
		execute(Request.CTRL_ROOM_REQ, params, "CTRL_ROOM_REQ");
	}
	
	@Override
	public void hangUpCalls(String confNumber, String[] calls) {
		Document doc=DocumentHelper.createDocument();
		Element root=doc.addElement(Request.HANGUP_CALLS_REQ);
		
		root.addElement("number").setText(confNumber);
		
		Element callsElement =new DOMElement("calls");
		for (int i = 0; i < calls.length; i++) {
			callsElement.addElement("callId").setText(calls[i]);
		}
		
		root.add(callsElement);
		
		execute(Request.HANGUP_CALLS_REQ, doc.asXML());
	}

        @Override
	public void inviteParticipants(String confNumber, String[] calls) {
		Document doc=DocumentHelper.createDocument();
		Element root=doc.addElement(Request.INVITE_PARTICIPANTS_REQ);

		root.addElement("number").setText(confNumber);

		Element callsElement =new DOMElement("calls");
		for (int i = 0; i < calls.length; i++) {
			callsElement.addElement("callId").setText(calls[i]);
		}

		root.add(callsElement);

		execute(Request.INVITE_PARTICIPANTS_REQ, doc.asXML());
	}
	
	@Override
	public void muteCalls(String confNumber, String[] calls, boolean mute) {
		Document doc=DocumentHelper.createDocument();
		Element root=doc.addElement(Request.MUTE_CALLS_REQ);
		
		root.addElement("number").setText(confNumber);
		root.addElement("mute").setText(String.valueOf(mute));
		
		Element callsElement =new DOMElement("calls");
		for (int i = 0; i < calls.length; i++) {
			callsElement.addElement("callId").setText(calls[i]);
		}
		
		root.add(callsElement);
		
		execute(Request.MUTE_CALLS_REQ, doc.asXML());
	}
	
	@Override
	public void specifyLecture(String confNumber, String callId, boolean cancel) {
		Map params=new HashMap<String, String>();
		params.put("number", confNumber);
		if(cancel){
			params.put("setLecture", "false");
		}else{
			params.put("setLecture", "true");
			params.put("lecture", callId);
		}
		
		execute(Request.CTRL_ROOM_REQ, params, Request.CTRL_ROOM_REQ);
	}
	
	@Override
	public CallDetail fetchCallDetail(String confNumber, String callId) {
		CallDetail ret=null;
		Map params=new HashMap<String, String>();
		params.put("number", confNumber);
		params.put("callId", callId);
		
		String receiveXML=execute(Request.GET_CALL_REQ, params, Request.GET_CALL_REQ);
		try {
			Document doc=DocumentHelper.parseText(receiveXML);
			
			ret=(CallDetail)DomainUtils.element2Domain(doc.getRootElement(), CallDetail.class);
		} catch (DocumentException e) {
			log.error(e.getMessage(),e);
			throw new DomainConvertException(e.getMessage());
		}
		
		return ret;
	}
	
	@Override
	public void inviteCalls(String confNumber,
			List<ConfParticipant> participants) {
		Document doc=DocumentHelper.createDocument();
		Element root=doc.addElement(Request.INVITE_CALLS_REQ);
		
		root.addElement("number").setText(confNumber);
		
		Element ptcsElement=new DOMElement("participants");
		
		for (Iterator iterator = participants.iterator(); iterator.hasNext();) {
			ConfParticipant confParticipant = (ConfParticipant) iterator.next();
			ptcsElement.add(DomainUtils.domain2Element("participant", confParticipant, ConfParticipant.INVITE_PARAM_FIELDS));
		}
		
		root.add(ptcsElement);
		
		execute(Request.INVITE_CALLS_REQ, doc.asXML());
	}
	
	@Override
	public List<BroadcastClient> queryBroadcastClients(String confNumber) {
		Map params=new HashMap<String, String>();
		params.put("number", confNumber);
		
		String receiveXML=execute(Request.GET_BROADCAST_REQ, params, Request.GET_BROADCAST_REQ);
		return DomainUtils.xml2List(receiveXML, "/clients/client", BroadcastClient.class);
	}
	
	@Override
	public List<ConfReservation> queryConfReservations() {
		String receiveXML=execute(Request.GET_RESERVATION_LIST_REQ);
		return DomainUtils.xml2List(receiveXML, "/reservations/reservation", ConfReservation.class);
	}
	
	@Override
	public void addConfReservation(ConfReservation reservation) {
		Document doc=DocumentHelper.createDocument();
		Element eReservation=DomainUtils.domain2Element("reservation", reservation, ConfReservation.ADD_FIELDS);
		doc.setRootElement(eReservation);
		
		Element participants=DocumentHelper.createElement("participants");
		for (Iterator iterator = reservation.getParticipants().iterator(); iterator
				.hasNext();) {
			ConfParticipant confParticipant = (ConfParticipant) iterator.next();
			participants.add(DomainUtils.domain2Element("participant", confParticipant, ConfParticipant.ADD_PARAM_FIELDS_FOR_RESERVATION));
		}
		
		if(participants.hasContent()){
			eReservation.add(participants);
		}
		
		execute(Request.ADD_RESERVATION_REQ, doc.asXML());
		
		sendEmailNotify(reservation);
	}
	
	@Override
	public void updateConfReservation(ConfReservation reservation) {
		Document doc=DocumentHelper.createDocument();
		Element root=DomainUtils.domain2Element("reservation", reservation, ConfReservation.UPDATE_FIELDS);
		doc.setRootElement(root);
		
		Element participants=DocumentHelper.createElement("participants");
		for (Iterator iterator = reservation.getParticipants().iterator(); iterator
				.hasNext();) {
			ConfParticipant confParticipant = (ConfParticipant) iterator.next();
			participants.add(DomainUtils.domain2Element("participant", confParticipant, ConfParticipant.UPDATE_PARAM_FIELDS_FOR_RESERVATION));
		}
		
		if(participants.hasContent()){
			root.add(participants);
		}
		
		execute(Request.PUT_RESERVATION_REQ, doc.asXML());
		
		sendEmailNotify(reservation);
	}
	/**
	 * Send email notify for conference reservation
	 * @param reservation
	 */
	private void sendEmailNotify(ConfReservation reservation){
		if(reservation!=null&&needSend(reservation)){
			List<ConfParticipant> confParticipants=reservation.getParticipants();
			SMTP smtp=setupService.getSMTP();
			for (Iterator iterator = confParticipants.iterator(); iterator.hasNext();) {
				ConfParticipant confParticipant = (ConfParticipant) iterator.next();
				String to=confParticipant.getP_email();
				
				if(StringUtils.hasText(to)&&smtp!=null){
					Email email=new Email();
					email.setSmtpServer(smtp.getHost());
					email.setFrom(smtp.getEmail());
					email.setTo(to);
					email.setVerify(smtp.getVerify()!=null&&smtp.getVerify().equals("true"));
					email.setAccount(smtp.getUser());
					email.setPwd(smtp.getPassword());
					email.setSubject(reservation.getEmailSubject(lang));
					email.setBody(reservation.getEmailBody(lang));
					
					EmailSender sender = new EmailSender(email);
					
					new Thread(sender).start();
				}
			}
		}
	}
	
	private boolean needSend(ConfReservation reservation) {
		return reservation.getEmailNotify() != null
				&& reservation.getEmailNotify().equals("true")
				&& !reservation.getParticipants().isEmpty();
	}
	
	@Override
	public ConfReservation getConfReservation(String id) {
		ConfReservation ret=null;
		Map params=new HashMap<String, String>();
		params.put("id", id);
		String receiveXML=execute(Request.GET_RESERVATION_REQ, params, "reservation");
		
		try {
			if(StringUtils.hasText(receiveXML)){
				Document doc=DocumentHelper.parseText(receiveXML);
				ret = (ConfReservation)DomainUtils.element2Domain(doc.getRootElement(), ConfReservation.class);
				
				List<ConfParticipant> list=new ArrayList<ConfParticipant>();
				List nodes=doc.selectNodes("/reservation/participants/participant");
				for (Iterator iterator = nodes.iterator(); iterator.hasNext();) {
					Element e = (Element) iterator.next();
					list.add((ConfParticipant)DomainUtils.element2Domain(e, ConfParticipant.class));
				}
				
				ret.setParticipants(list);
			}
		} catch (DocumentException e) {
			log.error(e.getMessage(),e);
			throw new DomainConvertException(e.getMessage());
		}
		
		return ret;
	}
	
	@Override
	public void removeConfReservation(String id) {
		if(StringUtils.hasText(id)){
			Map params=new HashMap<String, String>();
			params.put("id", id);
			execute(Request.DEL_RESERVATION_REQ,params,"reservation",true);
		}
	}
}
